﻿using System;
using System.Collections.Generic;
using System.Data.Services.Client;
using System.Linq;

using Caliburn.Micro;

using TheKitchen.Client.Commanding;
using TheKitchen.Client.Querying;

namespace TheKitchen.Client.Services
{
    public class QueryAgent : IHandle<ServicedCommand>, IQueryAgent
    {
        private readonly List<AddNewRecipeCommand> pendingAdditions = new List<AddNewRecipeCommand>();
        public Uri QueryContextUri = new Uri("http://localhost:9003/QueryService.svc");

        public QueryAgent(IEventAggregator eventAggregator)
        {
            eventAggregator.Subscribe(this);
        }

        public void FindRecipes(int? minimumRating, string partialName, string partialDescription, Action<IEnumerable<Recipe>> callback)
        {
            DataServiceQuery<Recipe> serviceQuery = ConstructQuery(minimumRating, partialName, partialDescription);

            serviceQuery.BeginExecute(asyncResult =>
            {
                List<Recipe> recipes = serviceQuery.EndExecute(asyncResult).ToList();

                AddNewRecipesStillPending(recipes);

                Execute.OnUIThread(() => callback(recipes));
            }, null);
        }

        private void AddNewRecipesStillPending(ICollection<Recipe> recipes)
        {
            foreach (var pendingAddition in pendingAdditions.ToArray())
            {
                if (!recipes.Any(r => r.Name == pendingAddition.Name ))
                {
                    recipes.Add(CreateTemporaryRecipe(pendingAddition));
                }
                else
                {
                    pendingAdditions.Remove(pendingAddition);
                }
            }
        }

        private static Recipe CreateTemporaryRecipe(AddNewRecipeCommand pendingAddition)
        {
            return new Recipe
            {
                Id = pendingAddition.Id,
                Name = pendingAddition.Name,
                Description = pendingAddition.Description,
                Rating = null,
                Version = 1
            };
        }

        private DataServiceQuery<Recipe> ConstructQuery(int? minimumRating, string partialName, string partialDescription)
        {
            var ctx = new QueryContext(QueryContextUri);
            var q = ctx.Recipes.Select(r => r);

            if (minimumRating > 0)
            {
                q = q.Where(r => r.Rating >= minimumRating);
            }

            if (!string.IsNullOrEmpty(partialName))
            {
                q = q.Where(r => r.Name.Contains(partialName));
            }

            if (!string.IsNullOrEmpty(partialDescription))
            {
                q = q.Where(r => r.Description.Contains(partialDescription));
            }

            return (DataServiceQuery<Recipe>)q;
        }

        public void Handle(ServicedCommand message)
        {
            if (message is AddNewRecipeCommand)
            {
                pendingAdditions.Add((AddNewRecipeCommand)message);
            }
        }
    }
}
